#!/bin/python3
# encoding=utf-8
from mpl_toolkits.axes_grid1 import host_subplot
import mpl_toolkits.axisartist as AA

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import math
import binascii
import os
import tkinter as tk
from tkinter import filedialog
'''
csv文件标题格式：
Capacity,Current,Volt,Temp
单位：
%，uA，mV，℃
'''
CHGTF=0x80
AEF=0x40
SEF=0x20
LEARNF=0x10
def draw(data, title="un title", index=[]):
    plt.figure('data')
    
    
    
    plt.subplot(4,1,1)
    plt.title(title)
    plt.ylabel("容量(%)")
    plt.plot(data[u"Capacity"])
    
    plt.subplot(4,1,2)
    plt.ylabel("电流(mA)")
    plt.plot(data[u"Current"])
    
    plt.subplot(4,1,3)
    plt.ylabel("电压(mV)")
    plt.plot(data[u"Volt"])
    
    plt.subplot(4,1,4)
    plt.ylabel("Status寄存器")
    plt.xlabel("时间(s)")
    plt.plot( (data["Status"] & 0x80), label="CHGTF(Bit7)")
    plt.plot( (data["Status"] & 0x40), label="AEF(Bit6)")
    plt.plot( (data["Status"] & 0x20), label="SEF(Bit5)")
    plt.plot( (data["Status"] & 0x10), label="LEARNF(Bit4)")
    plt.legend()

    pass

def draw_power(data, title="un title", index=[]):
    plt.figure('data')
    
    
    
    plt.subplot(3,2,1)
    plt.title(title)
    plt.ylabel("容量(%)")
    plt.plot(data[u"Capacity"])
    
    plt.subplot(3,2,3)
    plt.ylabel("电流(mA)")
    plt.plot(data[u"Current"])
    
    plt.subplot(3,2,5)
    plt.ylabel("电压(mV)")
    plt.plot(data[u"Volt"])
    
    
    # plt.ylabel("Status寄存器")
    # plt.xlabel("时间(s)")
    # plt.plot( (data["Status"] & 0x80), label="CHGTF(Bit7)")
    # plt.plot( (data["Status"] & 0x40), label="AEF(Bit6)")
    # plt.plot( (data["Status"] & 0x20), label="SEF(Bit5)")
    # plt.plot( (data["Status"] & 0x10), label="LEARNF(Bit4)")
    plt.legend()

    pass
def mark_text(data, string):
    Y = (min(data) + max(data)) / 2
    plt.text(0, Y,string)
    
def mark_on_figure(data, index):
    
    plt.subplot(4,1,1)
    plt.scatter(index, data["Capacity"][index],c='r')
    string = "%d~%d%%" %(data['Capacity'][index[0]], data['Capacity'][index[-1]])
    mark_text(data['Capacity'], string)
    
    plt.subplot(4,1,2)
    plt.scatter(index, data["Current"][index],c='r')
    string = "%d~%dmA" %(data['Current'][index[0]], data['Current'][index[-1]])
    mark_text(data['Current'], string)
    
    plt.subplot(4,1,3)
    plt.scatter(index, data["Volt"][index],c='r')
    string = "%d~%dmV" %(data['Volt'][index[0]], data['Volt'][index[-1]])
    mark_text(data['Volt'], string)
    
    # plt.subplot(4,1,4)
    # plt.scatter(index, data["Status"][index],c='r')
    # string = "%d~%dmV" %(data['Status'][index[0]], data['Status'][index[-1]])
    # mark_text(data['Status'], string)
    
    
    # print(data[u"Volt"][index])
    # for i in index:
    #     print("%3d%% %3.3dmA %4dmV" %(data['Capacity'][i], data['Current'][i], data['Volt'][i]))    

def _only_mark_on_figure(data, index):

    plt.subplot(3,2,1)
    plt.scatter(index, data["Capacity"][index],c='r')
    # string = "%d~%d%%" %(data['Capacity'][index[0]], data['Capacity'][index[-1]])
    # mark_text(data['Capacity'], string)
    
    plt.subplot(3,2,3)
    plt.scatter(index, data["Current"][index],c='r')
    # string = "%d~%dmA" %(data['Current'][index[0]], data['Current'][index[-1]])
    # mark_text(data['Current'], string)
    
    plt.subplot(3,2,5)
    plt.scatter(index, data["Volt"][index],c='r')
    # string = "%d~%dmV" %(data['Volt'][index[0]], data['Volt'][index[-1]])
    # mark_text(data['Volt'], string)
# 每列的输出范围
def range_element(data):
    print("波动范围")
    print("容量 %d ~ %dmV" %(np.min(data['Capacity']), np.max(data['Capacity'])))
    print("电流 %d ~ %dmV" %(np.min(abs(data['Current'])), np.max(abs(data['Current']))))
    print("电压 %d ~ %dmV" %(np.min(data['Volt']), np.max(data['Volt'])))
    
    # 电流最小值表示充电完毕
    min_A = np.min(abs(data['Current']))
    # 最大电压值
    max_V = np.max(data['Volt'])
    min_V = np.min(data['Volt'])


    index = np.where(data['Volt'] == min_V)[0][0]
    print("电压最小时:", end=' ')
    print("%3d%% %3.3dmA %4dmV" %(data['Capacity'][index], data['Current'][index], data['Volt'][index]))    
    index = np.where(data['Volt'] == max_V)[0][0]
    print("电压最大时:", end=' ')
    print("%3d%% %3.3dmA %4dmV" %(data['Capacity'][index], data['Current'][index], data['Volt'][index]))
    

    
    
def load_data(fname):
    fd = open(fname)
    data = pd.read_csv(fd)
    data["Current"] = data["Current"] / 1000
    data["Status"] = data["Status"].fillna("0")
    tlist = []
    K = iter(data["Status"])
    for i in K:
        tlist.append(int(i, 16))
    data["Status"] = np.array(tlist)
    
    data["Status"] = data["Status"].astype(int)

    tlist = []
    [tlist.append(int(i, 16)) for i in data["ACR"]]
    data["ACR"] = tlist
    return data

def check_charge_finish(data):
    print(data["Capacity"] == 100)


from scipy.optimize import leastsq
def error(p,x,y):
    return func(p,x)-y
def func(p,x):
    k,b=p
    return k*x+b

# 数据长度必须大于2小时，每秒一个点
def fun(data, before_shutdown_sec=30, run_sec=20, color='r'):
    before_shutdown_sec  = 60*before_shutdown_sec;  # 掉电前
    run_sec = 60 * run_sec;
    p0 = [1,20]
    the_range = list(range(len(data) - before_shutdown_sec - run_sec, len(data) - before_shutdown_sec))
    Xi=np.array(the_range)
    Yi=np.array(data[the_range])
    W=leastsq(error,p0,args=(Xi,Yi))[0]
    
    the_range = list(range(0, len(data)))
    Xi=np.array(the_range)
    Y1 = data
    Y2 = Xi * W[0] + W[1]
    
    # plt.plot(Xi, Y1)
    
    # plt.show()
    index = np.where(Y1 > Y2)[0][-1]
    plt.plot(Xi[index - 6000:index + 6000], Y2[index - 6000:index + 6000], c=color, alpha=1, linestyle=':')
    plt.scatter(index, Y2[index], c=color,   linewidths=5, alpha=1)
    return index
    
    
def draw_line(data, title=""):
    Y1 = data["Capacity"]
    Y2 = data['Volt']
    Y3 = data['Current']
    the_range = list(range(0, len(Y2)))
    Xi=np.array(the_range)

    
    
    
    fig = plt.figure()
    axL  = fig.add_subplot(111)
    axR = axL.twinx()
    axR2 = axL.twinx()
    
    plt.title(title + "放电点参考")
    axL.set_xlabel("时间(s)")
    axL.set_ylabel("容量(%)")
    axR.set_ylabel("电压(mV)")
    axR2.set_ylabel("电流(mA)")
    
    axL.plot(Xi, Y1, color='r')
    axR.plot(Xi, Y2, linewidth=3, color='b')
    axR2.plot(Xi, Y3, linewidth=3, color='b')
    axL.legend(labels=["容量"], loc='upper left')
    axR.legend(labels=["电压"], loc='upper right')
    axR2.legend(labels=["电流"], loc='upper right')
    
    
    # 绘制若干切线
    I = []
    I.append(fun(Y2, 60, 10, 'r'))
    I.append(fun(Y2, 40, 10, 'b'))
    I.append(fun(Y2, 30, 10, 'g'))
    I.append(fun(Y2, 20, 10, 'y'))
    # plt.legend(labels=['60min', '40min', '30min', '20min', '11'], loc='lower left')
    return I

def draw_3t1curve(data, title=""):
    title = os.path.basename(title)
    Y1 = data["Capacity"]
    Y2 = data['Current']
    Y3 = data['Volt']
    the_range = list(range(0, len(Y2)))
    Xi=np.array(the_range)

    
    
    
    fig = plt.figure()
    fig.set_size_inches(9.4,9.3)
    # fig.set_size_inches(10.0,10.0)
    axL = fig.add_subplot(211)
    axR = axL.twinx()
    axR2 = axL.twinx()
    
    
    plt.title(title)
    axL.set_xlabel("时间(s)")
    axL.set_ylabel("容量(%)")
    axR.set_ylabel("电流(mA)")
    axR.set_xlabel("时间(s)")
    axR2.set_ylabel("电压(mV)", labelpad=-4)
    axR2.spines['right'].set_position(('axes', 1.15))
    # print(axR2.spines)
    # axR2.set_frame_on(True)
    # axR2.patch.set_visible(False)
    
    
    lns1 = axL.plot(Xi, Y1, linewidth=3, linestyle="-",  color='r', alpha=0.8)
    lns2 = axR.plot(Xi, Y2, linewidth=1, linestyle="--",  color='g', alpha=0.8)
    lns3 = axR2.plot(Xi, Y3, linewidth=1, linestyle="-", color='b', alpha=0.8)
    lns = lns1+lns2+lns3
    # labs = [l.get_label() for l in lns]
    labs = ["容量", "电流", "电压" ]
    axL.legend(lns, labs)
    # axL.legend(labels=["容量", "电压", "电压1"], loc='upper left')
    # axR.legend(labels=["电压"], loc='upper right')
    # axR2.legend(labels=["电流"], loc='lower right')
    
    
    
    
    axL  = fig.add_subplot(413)
    fig.subplots_adjust(right=0.75, hspace=0.5)
    axL.set_title("电池状态")
    
    # Y1 = (int(data["Status"]) & 0x80)

    # Y2 = (data["Status"] & 0x40) >> 6 + 30;
    # Y3 = (data["Status"] & 0x20) >> 5 + 20;
    # Y4 = (data["Status"] & 0x10) >> 4 + 10;
    
    axL.plot( data["Status"] & 0x80, label="CHGTF(Bit7)")
    axL.plot( data["Status"] & 0x40, label="AEF(Bit6)")
    axL.plot( data["Status"] & 0x20, label="SEF(Bit5)")
    axL.plot( data["Status"] & 0x10, label="LEARNF(Bit4)")
    axL.set_xlabel("时间(s)")
    plt.yticks([])
    axL.legend()
    
    ax3  = fig.add_subplot(414)
    ax3.plot(data["ACR"])
    ax3.set_ylabel("ACR")
    ax3.set_xlabel("时间(s)")
    return fig, axL;
    
# 寻找放电块结束时的点
def min_volt_feature(data, title):
    I = draw_line(data['Volt'], title)
    pt = [60, 40, 30, 20]
    string=""
    for i in range(0, len(I)):
        string += "%dmin: %3.3dmV %3.3dmA\n" %(pt[i], data['Volt'][I[i]], data['Current'][I[i]])
    
    Y = (min(data['Volt']) + max(data['Volt'])) / 2
    plt.text(0, Y,string)
    
    
def show_index(data, index):
    # print("asf %d" %(data[index[0]]))
    print(data[index])
def chinese_code():
    plt.rcParams['font.sans-serif']=['SimHei']
    plt.rcParams['axes.unicode_minus'] = False
def integral(data, index):
    print("电流 %d" %sum(data['Current'][index]))
    print("电压 %d" %sum(data['Volt'][index]))

# 计算单位区域内功率的积分
def sum_power(data, index):
    
    return sum(data['Volt'][index] *data['Current'][index])

def draw_sum_power(data, title):
    draw_power(data,title=title)
    
    X = []
    for i in [0, 10, 20, 30, 40, 50, 60, 70, 80, 89]:
        index = np.where([
            [data['Capacity'] >= i],
            [data['Capacity'] <= i + 10],
        ])[-1]
        X.append(sum_power(data, index))
        _only_mark_on_figure(data, index=[index[0], index[-1]])
    # plt.figure()
    
    plt.subplot(3,2,2)
    plt.title("每10%功率积分")
    plt.plot(X)
    plt.show()
    
def select_csv():
    path = filedialog.askopenfile()
    if path != None:
        return path.name
    return None

def figure_3curve(data, index=[0,0], fname=""):
    
    fname = os.path.basename(fname)
    if len(index) > 2:
        title = fname + " Volt>3780 ID:" + str(index[0]) + "~" + str(index[-1])
    else:
        title = fname
    draw(data, title=title)
    if len(index) > 2:
        mark_on_figure(data, index=[index[0], index[-1]])
    plt.show()

def select_range(data):
    index = np.where([
        [data['Capacity'] <= 28],
        [data['Capacity'] >= 4],
    ])[-1]
    return index
def figure_discharge(data):
    # draw(data, title="title")
    draw_line(data, title="")
    plt.show()


def _only_mark_on_figure2(data, index, fig, axL):
    # axL  = fig.add_subplot(111)
    a = fig.get_axes()
    print(a)
    a[0].scatter(index, data["Capacity"][index],c='r')
    # string = "%d~%d%%" %(data['Capacity'][index[0]], data['Capacity'][index[-1]])
    # mark_text(data['Capacity'], string)
    
    # plt.subplot(3,2,3)
    # plt.scatter(index, data["Current"][index],c='r')
    # string = "%d~%dmA" %(data['Current'][index[0]], data['Current'][index[-1]])
    # mark_text(data['Current'], string)
    
    # plt.subplot(3,2,5)
    # plt.scatter(index, data["Volt"][index],c='r')
    
def figure_3t1curve(data, fname="", index=[0,0]):
    fig, axL = draw_3t1curve(data, title=fname)
    if index == [0,0]:
        pass
    else:
        _only_mark_on_figure2(data, index, fig, axL)
    plt.show()    
class dlg_battery:
    def __init__(self, master):
        self.root   = master
        self.frm_left   = tk.Frame(master = self.root)
        self.frm_left.grid(row=1, column=4)
        self._init_param_()
        self._init_left(self.frm_left)
    def _init_param_(self):
        self.data = None
        self.fname = None
    def _init_left(self, master):
        btn1 = tk.Button(master=master, text=u"打开文件" ,  width=10, height=3, bg="PaleGreen")
        btn2 = tk.Button(master=master, text=u"多曲线" ,  width=10, height=3, bg="PaleGreen")
        btn3 = tk.Button(master=master, text=u"放电特性" ,  width=10, height=3, bg="PaleGreen")
        btn4 = tk.Button(master=master, text=u"放电积分" ,  width=10, height=3, bg="PaleGreen")
        btn5 = tk.Button(master=master, text=u"TODO" ,  width=10, height=3, bg="PaleGreen")
        
        btn1.grid(row=0,column=0, padx=10)
        btn2.grid(row=0,column=1, padx=10)
        btn3.grid(row=0,column=2, padx=10)
        btn4.grid(row=0,column=3, padx=10)
        btn5.grid(row=0,column=4, padx=10)
        
        btn1.bind("<ButtonRelease-1>", self.on_btn1_click)
        btn2.bind("<ButtonRelease-1>", self.on_btn2_click)
        btn3.bind("<ButtonRelease-1>", self.on_btn3_click)
        btn4.bind("<ButtonRelease-1>", self.on_btn4_click)
        btn5.bind("<ButtonRelease-1>", self.on_btn5_click)
    def on_btn1_click(self, event):
        self.fname = select_csv()
        if self.fname == None:
            return None
    
        self.data = load_data(self.fname);
        pass
    def on_btn2_click(self, event):
        print(self.data)
        if self.data is None:
            self.on_btn1_click(None);
        index = np.where([
            [self.data['Capacity'] <= 28],
            [self.data['Capacity'] >= 4],
        ])[-1]
        figure_3curve(self.data, index);
        pass
    def on_btn3_click(self, event):
        if self.data is None:
            self.on_btn1_click(None);
        figure_discharge(self.data)
        pass
    def on_btn4_click(self, event):
        if self.data is None:
            self.on_btn1_click(None);
        # draw_power(self.data)
        draw_sum_power(self.data, title="")
        
        plt.show();
        pass
    def on_btn5_click(self, event):
        if self.data is None:
            self.on_btn1_click(None);
        # draw_3t1curve(self.data, title="")
        index = np.where([
            [self.data['Capacity'] <= 74],
            [self.data['Capacity'] >= 68],
        ])[-1]
        # figure_3t1curve(self.data, fname=self.fname, index=[index[0], index[-1]])
        figure_3t1curve(self.data, fname=self.fname, index=[0, 0])
        
        pass
    pass

if __name__ == '__main__':
    chinese_code()
    master = tk.Tk()
    dlg = dlg_battery(master)
    master.mainloop();
    exit(0)
    # fname = "./data/1-28-discharge.csv"
    # fname = "./data/1-29-discharge.csv"
    # fname = "./data/1-30-discharge.csv"
    
    
    # fname = "./data/1-29-charge.csv"
    # fname = "./data/1-30-charge.csv"
    # fname = "./data/2-19-3600-learn-well-discharge.csv"
    # fname = "./data/2-19-3600-learn-well-charge.csv"
    # fname = "./data/2-19-3600-learn-well-discharge.csv"
    # fname = "./data/2-19-acr-to-ffff-charge.csv"
    # fname = "./data/2-20-3600-3800.csv"
    fname = "./data/2-20-3800-3600.csv"
    
    fname = select_csv()
    if fname == None:
        exit(0)
    
    data = load_data(fname);
    
    
    index = np.where([
        [data['Status'] & CHGTF],
    ])[-1]


    index = np.where([
        [data['Capacity'] <= 28],
        [data['Capacity'] >= 4],
    ])[-1]
    # figure_3curve(data,fname=fname)
    figure_discharge(data);
    # index = np.where([
    #     [data['Volt'] >= 3760],
        
    # ])[-1]
    # min_volt_feature(data, fname)
    # title = "RARC报告100%，其实没满"
    # title = "Status寄存器报告满"
    # title = fname + " 5<=Capacity<=99 ID:" + str(index[0]) + "~" + str(index[-1])
    # title = fname + " Volt>3780 ID:" + str(index[0]) + "~" + str(index[-1])
    # title = fname + " CHGTF=1 ID:" + str(index[0]) + "~" + str(index[-1])
    # print(data["Status"])
    # draw(data,title=title)
    # mark_on_figure(data, index=[index[0], index[-1]])
    # title = fname + "功率每10%容量间隔积分"
    # draw_sum_power(data, title=title);
    
    # index = np.where([
    #     [data['Capacity'] >= 10],
    #     [data['Capacity'] <= 20],
    # ])[-1]
    # mark_on_figure(data, index=[index[0], index[-1]])
    # index = [1,20000,30000]
    # print(data['Volt'][index])
    # print(data['Current'][index])
